package com.ndood.oss.txyun.utils;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.model.CannedAccessControlList;
import com.qcloud.cos.model.CreateBucketRequest;
import com.qcloud.cos.model.GetObjectRequest;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.region.Region;

public class TxyunOSS {
	private static Logger logger = LoggerFactory.getLogger(TxyunOSS.class);
	/**
	 * 可用区
	 */
	private static final String REGION = PropertiesUtil.readProperty("txyun.cos.region");
	/**
	 * APPID
	 */
	private static final String APP_ID = PropertiesUtil.readProperty("txyun.cos.app-id");
	/**
	 * 阿里云API的密钥Access Key ID
	 */
	private static final String SECRET_ID = PropertiesUtil.readProperty("txyun.cos.secret-id");
	/**
	 * 阿里云API的密钥Access Key Secret
	 */
	private static final String SECRET_KEY = PropertiesUtil.readProperty("txyun.cos.secret-key");
	/**
	 * 阿里云API外网域名
	 */
	public static final String ENDPOINT = PropertiesUtil.readProperty("txyun.cos.endpoint");

	/**
	 * 懒汉，线程安全单例
	 */
	public static TxyunOSS getInstance() {
		return SingletonHolder.INSTANCE;
	}

	/**
	 * 静态内部类方式实现线程安全的懒汉单例
	 */
	private static class SingletonHolder {
		private static final TxyunOSS INSTANCE = new TxyunOSS();
	}

	/**
	 * 根据key获取url
	 */
	public String urlFromFileKey(String bucket, String folder, String fileName) {
		return "https://" + bucket + "-" + APP_ID + ".cos." + REGION + ".myqcloud.com" + "/" + folder + fileName;
	}

	/**
	 * 通过文件名判断并获取OSS服务文件上传时文件的contentType
	 */
	public String getContentType(String fileName) {
		// 文件的后缀名
		String fileExtension = fileName.substring(fileName.lastIndexOf("."));
		if (".bmp".equalsIgnoreCase(fileExtension)) {
			return "image/bmp";
		}
		if (".gif".equalsIgnoreCase(fileExtension)) {
			return "image/gif";
		}
		if (".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension)
				|| ".png".equalsIgnoreCase(fileExtension)) {
			return "image/jpeg";
		}
		if (".html".equalsIgnoreCase(fileExtension)) {
			return "text/html";
		}
		if (".txt".equalsIgnoreCase(fileExtension)) {
			return "text/plain";
		}
		if (".vsd".equalsIgnoreCase(fileExtension)) {
			return "application/vnd.visio";
		}
		if (".ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) {
			return "application/vnd.ms-powerpoint";
		}
		if (".doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) {
			return "application/msword";
		}
		if (".xml".equalsIgnoreCase(fileExtension)) {
			return "text/xml";
		}
		// 默认返回类型
		return "image/jpeg";
	}

	/**
	 * 创建客户端连接
	 */
	@SuppressWarnings("deprecation")
	private COSClient createCosClient() {
		// 1 初始化用户身份信息(secretId, secretKey)
		COSCredentials cred = new BasicCOSCredentials(APP_ID, SECRET_ID, SECRET_KEY);
		// 2 设置bucket的区域, COS地域的简称请参照
		// https://cloud.tencent.com/document/product/436/6224
		ClientConfig clientConfig = new ClientConfig(new Region(REGION));
		// 3 生成cos客户端
		COSClient cosclient = new COSClient(cred, clientConfig);
		return cosclient;
	}

	/**
	 * 创建存储空间Bucket
	 */
	public String createBucket(String bucket) {
		COSClient cosClient = createCosClient();

		if (!cosClient.doesBucketExist(bucket)) {
			// 创建存储空间
			CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucket);
			// 设置bucket权限为公共读，默认是私有读写
			createBucketRequest.setCannedAcl(CannedAccessControlList.PublicRead);
			cosClient.createBucket(createBucketRequest);
			logger.info("创建" + bucket + "Bucket成功！");
		}

		cosClient.shutdown();
		return bucket;
	}

	/**
	 * 删除存储空间
	 * @throws Exception 
	 */
	public void deleteBucket(String bucket) throws Exception {
		COSClient cosClient = createCosClient();

		try {
			cosClient.deleteBucket(bucket);
			logger.info("删除" + bucket + "Bucket成功！");
		} catch (Exception e) {
			logger.info("删除" + bucket + "Bucket失败："+e.getMessage());
			throw new Exception(e.getMessage());
		} finally{
			cosClient.shutdown();
		}

	}

	/**
	 * 创建文件夹
	 */
	public String createFolder(String bucket, String folder) {
		COSClient cosClient = createCosClient();

		// 判断文件夹是否存在，不存在则创建
		if (!cosClient.doesObjectExist(bucket, folder)) {
			// 创建上传Object的Metadata
			ObjectMetadata metadata = new ObjectMetadata();
			// 上传的文件的长度
			metadata.setContentLength(0);
			cosClient.putObject(bucket, folder, new ByteArrayInputStream(new byte[0]), metadata);
			logger.info("创建" + folder + "Folder成功！");
		}
		cosClient.shutdown();
		return folder;
	}

	/**
	 * 删除文件夹
	 */
	public void deleteFolder(String bucket, String folder) throws Exception {
		COSClient cosClient = createCosClient();

		// 判断文件夹是否存在，不存在则创建
		if (cosClient.doesObjectExist(bucket, folder)) {
			try {
				cosClient.deleteObject(bucket, folder);
				logger.info("删除" + folder + "Folder成功！");
			} catch (Exception e) {
				logger.info("删除" + folder + "Folder失败:"+e.getMessage());
				throw new Exception(e.getMessage());
			} finally{
				cosClient.shutdown();
			}
		}
	}

	/**
	 * 下载文件到本地
	 */
	public String getObject(String bucket, String folder, String fileName, String localPath) {
		COSClient cosClient = createCosClient();

		String localFileKey = localPath + folder + fileName;
		// 指定要下载到的本地路径
		cosClient.getObject(new GetObjectRequest(bucket, folder + fileName), new File(localFileKey));
		logger.info("从OSS下载文件成功！", localFileKey);

		cosClient.shutdown();
		return localFileKey;
	}

	/**
	 * 删除存储对象
	 */
	public void deleteObject(String bucket, String folder, String fileName) throws Exception {
		COSClient cosClient = createCosClient();

		try {
			cosClient.deleteObject(bucket, folder + fileName);
			logger.info("删除" + bucket + "下的文件" + folder + fileName + "成功！");
		} catch (Exception e) {
			logger.info("删除" + bucket + "下的文件" + folder + fileName + "失败："+e.getMessage());
			throw new Exception(e.getMessage());
		} finally{
			cosClient.shutdown();
		}
	}

	/**
	 * 检查文件是否存在
	 */
	public boolean checkObject(String bucket, String folder, String fileName) {
		COSClient cosClient = createCosClient();

		boolean ok = cosClient.doesObjectExist(bucket, folder + fileName);

		cosClient.shutdown();
		return ok;
	}

	/**
	 * 上传文件
	 */
	public String upload(String bucket, String folder, MultipartFile file) {
		COSClient cosClient = createCosClient();

		try {
			// 以输入流的形式上传文件
			InputStream is = file.getInputStream();
			// 文件名
			String fileName = file.getOriginalFilename();
			// 文件大小
			Long fileSize = file.getSize();
			// 创建上传Object的Metadata
			ObjectMetadata metadata = new ObjectMetadata();
			// 上传的文件的长度
			metadata.setContentLength(is.available());
			// 指定该Object被下载时的网页的缓存行为
			metadata.setCacheControl("no-cache");
			// 指定该Object下设置Header
			metadata.setHeader("Pragma", "no-cache");
			// 指定该Object被下载时的内容编码格式
			metadata.setContentEncoding("utf-8");
			// 文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
			// 如果没有扩展名则填默认值application/octet-stream
			metadata.setContentType(getContentType(fileName));
			// 指定该Object被下载时的名称（指示MINME用户代理如何显示附加的文件，打开或下载，及文件名称）
			metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");
			// 重命名文件
			fileName = DateUtils.getCurrentTimestamp() + fileName;
			// 上传文件 (上传文件流的形式)
			cosClient.putObject(bucket, folder + fileName, is, metadata);

			return urlFromFileKey(bucket, folder, fileName);
		} catch (Exception e) {
			logger.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
			return null;
		} finally {
			cosClient.shutdown();
		}
	}

	/**
	 * 上传文件
	 */
	public String upload(String bucket, String folder, File file) {
		COSClient cosClient = createCosClient();

		try {
			// 以输入流的形式上传文件
			InputStream is = new FileInputStream(file);
			// 文件名
			String fileName = file.getName();
			// 文件大小
			Long fileSize = file.length();
			// 创建上传Object的Metadata
			ObjectMetadata metadata = new ObjectMetadata();
			// 上传的文件的长度
			metadata.setContentLength(is.available());
			// 指定该Object被下载时的网页的缓存行为
			metadata.setCacheControl("no-cache");
			// 指定该Object下设置Header
			metadata.setHeader("Pragma", "no-cache");
			// 指定该Object被下载时的内容编码格式
			metadata.setContentEncoding("utf-8");
			// 文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
			// 如果没有扩展名则填默认值application/octet-stream
			metadata.setContentType(getContentType(fileName));
			// 指定该Object被下载时的名称（指示MINME用户代理如何显示附加的文件，打开或下载，及文件名称）
			metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");
			// 重命名文件
			fileName = DateUtils.getCurrentTimestamp() + fileName;
			// 上传文件 (上传文件流的形式)
			cosClient.putObject(bucket, folder + fileName, is, metadata);
			// 解析结果
			return urlFromFileKey(bucket, folder, fileName);
		} catch (Exception e) {
			logger.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
			return null;
		} finally {
			cosClient.shutdown();
		}
	}

	public static void main(String[] args) throws Exception {
		TxyunOSS cos = TxyunOSS.getInstance();
		// Step1： 创建bucket ndood_bucket
		cos.createBucket("ndoodbucket");
		// Step2: 创建folder ndood_folder
		cos.createFolder("ndoodbucket", "test/");
		// Step3: 上传文件到ndood_folder
		String url = cos.upload("ndoodbucket", "test/", new File("C:\\Users\\Administrator\\Desktop\\111.png"));
		System.out.println(url);
		// Step4: 删除文件 
		cos.deleteObject("ndoodbucket", "test/", "20180310161610967111.png"); 
		// Step5: 删除文件夹
		cos.deleteFolder("ndoodbucket", "test/");
		// Step6: 删除bucket
		cos.deleteBucket("ndoodbucket");
	}

}
